<?php

/**
 * HttpRequest. Send requests over HTTP (proxy is supported, and proxy-auth too)
 *
 * @author vbolshov
 */

namespace km\net;

class HttpRequest {
	/**
	 * @var string
	 */
	private $url, $proxy;
	/**
	 * @var string
	 */
	private $method;
	/**
	 * @var array
	 */
	private $data;
	/**
	 * Headers to send
	 * @var array
	 */
	private $headers = array();
	/**
	 * @param string $url
	 * @param string $method
	 * @return void
	 * @throws NetworkException
	 */
	function __construct($url, $method = 'GET')
	{
		$this->url = $url;
		$this->method = $method;
	}
	/**
	 * @param $name
	 * @param $value
	 * @return HttpRequest support fluent interface
	 */
	function addHeader($name, $value)
	{
		$this->headers[$name] = $value;
		return $this;
	}
	/**
	 * @param $name
	 * @return HttpRequest support fluent interface
	 */
	function removeHeader($name)
	{
		if (isset($this->headers[$name])) {
			unset($this->headers[$name]);
		}
		return $this;
	}
	/**
	 * @param string $proxy
	 * @return void
	 */
	function setProxy($proxy)
	{
		$this->proxy = $proxy;
	}
	
	/**
	 * Send the request
	 * @return array (BODY, HEADERS)
	 */
	function send()
	{
		if ('POST' == $this->method)
		{
			$post_data = ($this->data && count($this->data)) ? http_build_query($this->data, '', '&') : '';
			$content_type = "Content-Type: application/x-www-form-urlencoded\r\n";
			$content_length = "Content-Length: " . strlen($post_data) . "\r\n";
		} else {
			$content_type = $content_length = $post_data = '';
		}

		$opts = array('http' =>
			array(
				'method'  => $this->method,
				'header'  => $content_type . $content_length,
				'content' => $post_data,
				'max_redirects' => 5
			)
		);
		
		if ($this->proxy)
		{
			$opts['proxy'] = $this->proxy;
		}
		
		foreach ($this->headers as $name => $value) {
			$opts['http']['header'] .= $name . ': ' . $value . "\r\n";
		}

		$context = stream_context_create($opts);
		if (! $fp = fopen($this->url, 'r', false, $context)) {
			throw new NetworkException("Cannot connect to {$this->url}");
		}
		
		$meta_data = stream_get_meta_data($fp);
		$headers = implode("\r\n", $meta_data['wrapper_data']);
		$body = "";

		while (! feof($fp)) {
			$body .= fread($fp, 1024);
		}
		
		return array($body, $headers);
	}
	/**
	 * Set data to be sent as POST body (implicitly sets request method to POST)
	 * @param $data
	 * @return void
	 */
	function setData(array $data)
	{
		$this->method = 'POST';
		$this->data = $data;
	}
}